package com.hsjk.szwj.module.train.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hsjk.szwj.framework.common.constant.CommonConstant;
import com.hsjk.szwj.framework.common.pojo.PageResult;
import com.hsjk.szwj.framework.mq.core.RedisDelayedQueue;
import com.hsjk.szwj.framework.security.core.LoginUser;
import com.hsjk.szwj.framework.security.core.util.SecurityFrameworkUtils;
import com.hsjk.szwj.framework.tenant.core.aop.TenantIgnore;
import com.hsjk.szwj.framework.tenant.core.context.TenantContextHolder;
import com.hsjk.szwj.module.system.api.service.IServiceApi;
import com.hsjk.szwj.module.system.api.service.dto.ServiceDTO;
import com.hsjk.szwj.module.train.api.IClassApi;
import com.hsjk.szwj.module.train.api.ICourseApi;
import com.hsjk.szwj.module.train.api.IMemberServiceApi;
import com.hsjk.szwj.module.train.api.IProductApi;
import com.hsjk.szwj.module.train.api.IStudentApi;
import com.hsjk.szwj.module.train.api.dto.ClassDTO;
import com.hsjk.szwj.module.train.api.dto.CourseDTO;
import com.hsjk.szwj.module.train.api.dto.MemberCourseMappingDTO;
import com.hsjk.szwj.module.train.api.dto.MemberServiceMappingDTO;
import com.hsjk.szwj.module.train.api.dto.ProductSkuBindDTO;
import com.hsjk.szwj.module.train.api.dto.StudentInfoDTO;
import com.hsjk.szwj.module.train.controller.admin.vo.AdminOrderPageReqVO;
import com.hsjk.szwj.module.train.controller.admin.vo.AdminOrderPageRespVO;
import com.hsjk.szwj.module.train.controller.app.vo.order.OrderBasicInfoRespVO;
import com.hsjk.szwj.module.train.controller.app.vo.order.OrderCreateReqVO;
import com.hsjk.szwj.module.train.controller.app.vo.order.OrderInfoRespVO;
import com.hsjk.szwj.module.train.controller.app.vo.order.OrderListRespVO;
import com.hsjk.szwj.module.train.convert.OrderConvert;
import com.hsjk.szwj.module.train.dal.dataobject.mq.OrderFailureTimeMQ;
import com.hsjk.szwj.module.train.dal.dataobject.order.OrderDO;
import com.hsjk.szwj.module.train.dal.dataobject.product.ProductSkuBindDO;
import com.hsjk.szwj.module.train.dal.dataobject.product.ProductSkuDO;
import com.hsjk.szwj.module.train.dal.mysql.order.IOrderMapper;
import com.hsjk.szwj.module.train.dal.mysql.product.IProductSkuBindMapper;
import com.hsjk.szwj.module.train.dal.mysql.product.IProductSkuMapper;
import com.hsjk.szwj.module.train.enums.OrderCancelTypeEnum;
import com.hsjk.szwj.module.train.enums.OrderSkuSourceEnum;
import com.hsjk.szwj.module.train.enums.OrderStatusEnum;
import com.hsjk.szwj.module.train.enums.OrderTypeEnum;
import com.hsjk.szwj.module.train.mq.delayed.OrderFailureTimeListener;
import com.hsjk.szwj.module.train.service.IOrderService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenjiawei
 * @desc
 * @Date 2023/08/28 11:21
 **/
@Service
public class OrderServiceImpl implements IOrderService {
    @Resource
    private IOrderMapper orderMapper;

    @Resource
    private IProductSkuMapper productSkuMapper;

    @Resource
    private IProductSkuBindMapper productSkuBindMapper;

    @Resource
    private IProductApi productApi;

    @Resource
    private ICourseApi courseApi;
    @Resource
    private IServiceApi serviceApi;
    @Resource
    private IClassApi classApi;
    @Resource
    private IMemberServiceApi memberServiceApi;
    @Resource
    private IStudentApi studentApi;

    @Resource
    private RedisDelayedQueue redisDelayedQueue;


    @Value("${szwj.order.failure-time}")
    private String orderFailureTime;

    @Value("${szwj.platform-tenant-id}")
    private String platformTenantId;

    @Override
    public Long createOrder(OrderCreateReqVO reqVO) {
        OrderDO orderDO = OrderConvert.INSTANCE.convertOrderDO(reqVO);
        orderDO.setOrderNo(IdUtil.getSnowflakeNextIdStr());
        orderDO.setSkuSource(OrderSkuSourceEnum.PLATFORM.getValue());
        orderDO.setOrderType(OrderTypeEnum.ONLINE.getValue());
        //如果订单金额为0的直接完成状态
        if (orderDO.getOrderPrice() == 0) {
            orderDO.setStatus(OrderStatusEnum.PAYED.getValue());
            orderDO.setPayTime(LocalDateTime.now());
            Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
            Long tenantId = TenantContextHolder.getTenantId();
            //开通服务
            List<ProductSkuBindDTO> productSkuBindListBySkuId = productApi.getProductSkuBindListBySkuId(orderDO.getSkuId());
            if (CollUtil.isNotEmpty(productSkuBindListBySkuId)) {
                for (ProductSkuBindDTO bindDTO : productSkuBindListBySkuId) {
                    if (CommonConstant.PRODUCT_SKU_BIND_TYPE_COURSE.equals(bindDTO.getBindType())) {
                        CourseDTO courseById = courseApi.getCourseById(bindDTO.getBindId());
                        if (ObjectUtil.isNotNull(courseById)) {
                            MemberCourseMappingDTO dto = new MemberCourseMappingDTO();
                            dto.setCourseId(bindDTO.getBindId());
                            dto.setMemberId(loginUserId);
                            dto.setValidDays(courseById.getValidDays());
                            dto.setTenantId(tenantId);
                            courseApi.createMemberCourseMapping(dto);
                        }
                    } else if (CommonConstant.PRODUCT_SKU_BIND_TYPE_SERVICE.equals(bindDTO.getBindType())) {
                        ServiceDTO serviceById = serviceApi.getServiceById(bindDTO.getBindId());
                        if (ObjectUtil.isNotNull(serviceById)) {
                            MemberServiceMappingDTO serviceMappingDTO = new MemberServiceMappingDTO();
                            serviceMappingDTO.setServiceId(bindDTO.getBindId());
                            serviceMappingDTO.setMemberId(loginUserId);
                            serviceMappingDTO.setValidDays(serviceById.getValidDays());
                            serviceMappingDTO.setTenantId(tenantId);
                            memberServiceApi.createMemberServiceMapping(serviceMappingDTO);
                        }
                    } else if (CommonConstant.PRODUCT_SKU_BIND_TYPE_CLASS.equals(bindDTO.getBindType())) {
                        ClassDTO classById = classApi.getClassById(bindDTO.getBindId());
                        if (ObjectUtil.isNotNull(classById)) {
                            String signUpInfo = orderDO.getSignUpInfo();
                            if (StrUtil.isNotBlank(signUpInfo)) {
                                JSONObject jsonObject = JSONUtil.parseObj(signUpInfo);
                                if (ObjectUtil.isNotNull(jsonObject)) {
                                    StudentInfoDTO studentInfoDTO = new StudentInfoDTO();
                                    studentInfoDTO.setGender(Integer.valueOf(jsonObject.getStr("gender")));
                                    studentInfoDTO.setName(jsonObject.getStr("name"));
                                    studentInfoDTO.setPhone(jsonObject.getStr("phone"));
                                    studentInfoDTO.setCarType(classById.getCarType());
                                    studentInfoDTO.setTenantId(tenantId);
                                    studentApi.createStudentInfo(studentInfoDTO);
                                }
                            }
                        }
                    }
                }
            }
        } else {
            orderDO.setStatus(OrderStatusEnum.WAIT_PAY.getValue());
        }
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        if (ObjectUtil.isNotNull(user)) {
            orderDO.setMemberId(user.getId());
        }
        orderMapper.insert(orderDO);
        //创建订单延时失效处理MQ 订单10分钟失效
        OrderFailureTimeMQ orderFailureTimeMQ = new OrderFailureTimeMQ();
        orderFailureTimeMQ.setOrderId(orderDO.getPayOrderId());
        redisDelayedQueue.addQueueSeconds(orderFailureTimeMQ,
                Long.valueOf(orderFailureTime) + 60, OrderFailureTimeListener.class);
        return orderDO.getId();
    }

    @Override
    public OrderInfoRespVO getOrderInfoById(Long id) {
        OrderInfoRespVO respVO = new OrderInfoRespVO();
        OrderDO orderDO = orderMapper.selectById(id);
        if (ObjectUtil.isNotNull(orderDO)) {
            respVO = OrderConvert.INSTANCE.convertOrderInfoRespVO(orderDO);
            ProductSkuDO productSkuDO = productSkuMapper.selectById(orderDO.getSkuId());
            if (ObjectUtil.isNotNull(productSkuDO)) {
                respVO.setSkuInfo(OrderConvert.INSTANCE.convertOrderSkuInfoRespVO(productSkuDO));
                List<ProductSkuBindDO> productSkuBindDOS = productSkuBindMapper.selectListBySkuId(productSkuDO.getId());
                if (CollUtil.isNotEmpty(productSkuBindDOS)) {
                    respVO.getSkuInfo().setSkuBindList(OrderConvert.INSTANCE.convertOrderSkuBindInfoList(productSkuBindDOS));
                }
            }
        }
        return respVO;
    }

    @Override
    @TenantIgnore
    public OrderDO getOrderInfoByIdIgnoreTenant(Long id) {
        return orderMapper.selectById(id);
    }

    @Override
    public OrderInfoRespVO getOrderInfoByOrderNo(String orderNo) {
        OrderInfoRespVO respVO = new OrderInfoRespVO();
        OrderDO orderDO = orderMapper.selectOne(OrderDO::getOrderNo, orderNo);
        if (ObjectUtil.isNotNull(orderDO)) {
            respVO = OrderConvert.INSTANCE.convertOrderInfoRespVO(orderDO);
            ProductSkuDO productSkuDO = productSkuMapper.selectById(orderDO.getSkuId());
            if (ObjectUtil.isNotNull(productSkuDO)) {
                respVO.setSkuInfo(OrderConvert.INSTANCE.convertOrderSkuInfoRespVO(productSkuDO));
                List<ProductSkuBindDO> productSkuBindDOS = productSkuBindMapper.selectListBySkuId(productSkuDO.getId());
                if (CollUtil.isNotEmpty(productSkuBindDOS)) {
                    respVO.getSkuInfo().setSkuBindList(OrderConvert.INSTANCE.convertOrderSkuBindInfoList(productSkuBindDOS));
                }
            }
        }
        return respVO;
    }

    @Override
    public boolean cancelOrder(Long id) {
        OrderDO orderDO = new OrderDO();
        orderDO.setId(id);
        orderDO.setStatus(OrderStatusEnum.CANCEL.getValue());
        orderDO.setCancelType(OrderCancelTypeEnum.MEMBER.getValue());
        return orderMapper.updateById(orderDO) > 0;
    }

    @Override
    @TenantIgnore
    public List<OrderListRespVO> getOrderListByMemberId() {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if (ObjectUtil.isNotNull(loginUser)) {
            return orderMapper.getOrderListByMemberId(loginUser.getId());
        }
        return new ArrayList<>();
    }

    @Override
    @TenantIgnore
    public OrderBasicInfoRespVO getOrderBasicInfoByPayOrderId(String payOrderId) {
        OrderDO orderDO = orderMapper.selectOne(OrderDO::getPayOrderId, payOrderId);
        return OrderConvert.INSTANCE.convert(orderDO);
    }

    @Override
    @TenantIgnore
    public PageResult<AdminOrderPageRespVO> getAdminOrderPage(AdminOrderPageReqVO reqVO) {
        List<Long> tenantIds = new ArrayList<>();
        Long tenantId = TenantContextHolder.getTenantId();
        if (ObjectUtil.isNotNull(tenantId)) {
            tenantIds.add(tenantId);
        }
        if (ObjectUtil.isNotNull(platformTenantId)) {
            tenantIds.add(Long.valueOf(platformTenantId));
        }
        Page<AdminOrderPageReqVO> page = new Page<>(reqVO.getPageNo(), reqVO.getPageSize());
        IPage<AdminOrderPageRespVO> adminOrderPage = orderMapper.getAdminOrderPage(page, reqVO, tenantIds);
        return new PageResult<>(adminOrderPage.getRecords(), adminOrderPage.getTotal());
    }

    @Override
    public Boolean failureTimeCancelOrder(Long id) {
        OrderDO orderDO = new OrderDO();
        orderDO.setId(id);
        orderDO.setStatus(OrderStatusEnum.CANCEL.getValue());
        orderDO.setCancelType(OrderCancelTypeEnum.SYSTEM.getValue());
        return orderMapper.updateById(orderDO) > 0;
    }

    @Override
    public void deleteOrder(Long id) {
        orderMapper.deleteById(id);
    }

}
